#include "text.h"

using namespace std;
using namespace xercesc;

Text::Text()
{
}
bool Text::isLetter(char a)
{
	if(a >= 'a' && a <= 'z') 
		return true;
	if(a >= 'A' && a <= 'Z')
		return true;
	return false;
}
size_t Text::wordCount(string const & text) 
{
	size_t word_num = 0;
	size_t text_len = text.size();
	for(size_t i = 0; i < text_len; ++i)
	{
		if(i + 1 < text_len && isLetter(text[i]) && !isLetter(text[i+1]))
		{
			++word_num;
		}
	}
	if(text_len > 0 && isLetter(text[text_len - 1]) )
		++word_num;
	return word_num;
}

TxtText::TxtText()
{
}
size_t TxtText::readText(string const & file_name) 
{
	bool all_good = true;
	size_t word_num = 0;
	try
	{
		ifstream in(file_name.c_str());
		if(!in.is_open())
		{
			all_good = false;
			throw ios_base::failure("Cannot open file");	
		}
		size_t length = 1000;
		vector<char> buff (length + 1, 0);
		while(!in.eof())
		{
			in.read(&buff[0], buff.size());
			if(in.bad())
			{
				throw ios_base::failure ("Unexpected end of file");
			}
			while(isLetter(buff[buff.size() - 1]))
			{
				buff.push_back(' ');
				in.get(buff[buff.size() - 1]);
				if(in.bad())
				{
					throw ios_base::failure ("Unexpected end of file");
				}
			}
			for(size_t i = 0; i < buff.size(); ++i)
			{
				if(buff[i] == 10) buff[i] = ' ';
			}
			if(buff[buff.size() - 1]) buff.push_back(0);
			word_num += wordCount(&buff[0]);
			if(buff.size() > length * 3) buff.resize(length + 1);
			fill(buff.begin(), buff.end(), 0);
		}
		in.close();
	}
	catch(ios_base::failure & e)
	{
		all_good = false;
		cerr << e.what() << '\n';
	}
	catch(...)
	{
		all_good = false;
	}
	if(all_good)
	{
		cout << "File read correctly\n";
		cout << "Total number of words is " << word_num << endl;
		return word_num;
	}
	else
	{
		cout << "Some problems appeared while reading file\n";
		cout << "Partial number of words is " << word_num <<endl;
		return word_num;
	}
}

XmlText::XmlText()
	:word_num(0)
{
	XMLPlatformUtils::Initialize();
}
XmlText::~XmlText()
{
	XMLPlatformUtils::Terminate();
}

void XmlText::startElement(const   XMLCh* const    uri, const   XMLCh* const    localname, const   XMLCh* const    qname, const   Attributes&     attrs )
{
	for(size_t i = 0; i < attrs.getLength(); ++i)
	{
		XMLStrToStr(XMLString::transcode(attrs.getValue(i)), buffer);
		buffer += ' ';
	}
}
void XmlText::endElement(const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname)
{
	buffer += ' ';
	if(buffer.size() > 8192)
		word_num += wordCount(buffer);
}
void XmlText::XMLStrToStr(char * line, string & str)
{
	char * new_i = line;
	while(*new_i)
	{
		str += *new_i;
		++new_i;
	}
}
void XmlText::characters (const XMLCh *const chars, const XMLSize_t length)
{
	XMLStrToStr(XMLString::transcode(chars), buffer);
}
void XmlText::endDocument()
{
	if(buffer.size() > 0 )
	{
		word_num += wordCount(buffer);
	}
}
size_t XmlText::readText(std::string const & file_name)
{
	bool all_good = true;
	
	try
	{
		
		SAX2XMLReader * parser = XMLReaderFactory::createXMLReader();
		parser -> setContentHandler(this);
		parser -> parse( file_name.c_str());
	}
	catch (const XMLException& toCatch) {
		all_good = false;
		char* message = XMLString::transcode(toCatch.getMessage());
		cerr << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
	}
	catch (const SAXParseException& toCatch) {
		all_good = false;
		char* message = XMLString::transcode(toCatch.getMessage());
		cerr << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
	}
	catch(ios_base::failure & e)
	{
		all_good = false;
		cerr << e.what() << '\n';
	}
	catch(logic_error & le)
	{
		all_good = false;
		cerr <<le.what() << '\n';
	}
	catch(...)
	{
		all_good = false;
	}
	if(all_good)
	{
		cout << "File read correctly\n";
		cout << "Total number of words is " << word_num << endl;
		return word_num;
	}
	else
	{
		cout << "Some problems appeared while reading file\n";
		cout << "Partial number of words is " << word_num <<endl;
		return word_num;
	}
	return 0;
}